import { authenticateResponseInterceptor, AxiosClient, errorMessageResponseInterceptor, HttpResponse } from "@scpun/axios";
import { isString, TokenInfo } from "@scpun/core";
import { useAccessStore, useOAuth2Store } from "@scpun/stores";
import { useAuthenticationStore } from "../store/modules";
import { refreshToken } from "./oauth2";

const apiURL = import.meta.env.VITE_API_URL;

function createHttpClient(baseURL: string) {
    const axiosClient = new AxiosClient({ baseURL });

    // 请求头处理
    axiosClient.addRequestInterceptor({
        fulfilled: async (config) => {
            const oauth2Store = useOAuth2Store();
            config.headers.Authorization = formatToken(oauth2Store.storeTokenInfo);
            // config.headers["Accept-Language"] = 语言类型
            return config;
        },
    });

    // response数据解构<
    axiosClient.addResponseInterceptor<HttpResponse<any>>({
        fulfilled: (response) => {
            const { data: responseData, status } = response;
            if (status >= 200 && status < 400) {
                if (Reflect.has(responseData, "code")) {
                    const { code, data } = responseData;
                    if (code === 0) {
                        return data;
                    }
                } else {
                    return responseData;
                }
            }
            throw Object.assign({}, response, { response });
        },
    });

    // token过期的处理
    axiosClient.addResponseInterceptor(
        authenticateResponseInterceptor({
            client: axiosClient,
            doReAuthenticate,
            doRefreshToken,
            enableRefreshToken: true,
            formatToken,
        })
    );

    // 通用的错误处理,如果没有进入上面的错误处理逻辑，就会进入这里
    axiosClient.addResponseInterceptor(
        errorMessageResponseInterceptor((msg: string, error) => {
            // 这里可以根据业务进行定制,你可以拿到 error 内的信息进行定制化处理，根据不同的 code 做不同的提示，而不是直接使用 message.error 提示 msg
            // 当前mock接口返回的错误字段是 error 或者 message
            const responseData = error?.response?.data ?? {};
            const errorMessage = responseData?.error ?? responseData?.message ?? "";
            // 如果没有错误信息，则会根据状态码进行提示
            window.$message?.error(errorMessage || msg);
        })
    );

    function formatToken(token: Nullable<TokenInfo> | string): null | string {
        if (token) {
            if (isString(token)) {
                return `Bearer ${token}`;
            } else {
                const { access_token, token_type } = token;
                return `${token_type} ${access_token}`;
            }
        }
        return token;
    }

    async function doReAuthenticate(): Promise<void> {
        console.warn("Access token or refresh token is invalid or expired. ");
        const accessStore = useAccessStore();
        const oauth2Store = useOAuth2Store();
        const authenticationStore = useAuthenticationStore();
        accessStore.setAccessToken(null);
        oauth2Store.setTokenInfo(null);
        if (accessStore.isAccessChecked) {
            accessStore.setLoginExpired(true);
        } else {
            await authenticationStore.logout();
        }
    }

    async function doRefreshToken(): Promise<string> {
        const accessStore = useAccessStore();
        const resp = await refreshToken(accessStore.refreshToken as string);
        const newToken: TokenInfo = resp.data;
        if (newToken) {
            accessStore.setAccessToken(newToken.access_token);
            accessStore.setRefreshToken(newToken.refresh_token);

            const oauth2Store = useOAuth2Store();
            oauth2Store.setTokenInfo(newToken);
        }
        return newToken?.access_token;
    }

    return axiosClient;
}

const httpClient = createHttpClient(apiURL);

export { httpClient };
